use std::fmt::Display;

use serde::{Deserialize, Serialize};

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct MenuItem {
    pub id: u32,
    pub name: String,
    #[serde(default)]
    pub component: Option<Component>,
    #[serde(default)]
    pub permission: Option<Permission>,
    #[serde(default)]
    pub children: Vec<MenuItem>,
}
impl MenuItem {
    pub fn find_item(&self, id: u32) -> Option<&MenuItem> {
        if self.id == id {
            return Some(self);
        }
        for child in &self.children {
            if let Some(item) = child.find_item(id) {
                return Some(item);
            }
        }
        None
    }
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Component {
    pub kind: String,
    pub conf: String,
    #[serde(default)]
    pub icon: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Permission {
    pub auth_types: Vec<AuthType>,
    #[serde(default)]
    pub row_ranges: Vec<RowRange>,
    #[serde(default)]
    pub column_ranges: Vec<ColumnRange>,
}
impl Default for Permission {
    fn default() -> Self {
        Self {
            auth_types: vec![AuthType::Select],
            row_ranges: vec![RowRange::OneSelf],
            column_ranges: vec![],
        }
    }
}
#[cfg(feature = "ssr")]
impl Permission {
    pub fn from_str(
        perm_str: &str,
    ) -> anyhow::Result<Self> {
        let mut auth_types = Vec::new();
        let mut row_ranges = Vec::new();
        let mut column_ranges = Vec::new();
        let parts: Vec<&str> = perm_str.split('|').collect();
        if parts.len() != 3 {
            return Err(anyhow::anyhow!("Invalid permission string"));
        }
        let ats: Vec<&str>=parts[0].split(',').collect();
        for at in ats {
            let at = at.trim();
            if at.is_empty() {
                continue;
            }
            let at = at.parse::<u8>()?;
            auth_types.push(AuthType::from(at));
        }
        let rrs: Vec<&str>=parts[1].split(',').collect();
        for rr in rrs {
            let rr = rr.trim();
            if rr.is_empty() {
                continue;
            }
            let rr = rr.parse::<u8>()?;
            row_ranges.push(RowRange::from(rr));
        }
        let crs: Vec<&str>=parts[2].split(',').collect();
        for cr in crs {
            let cr = cr.trim();
            if cr.is_empty() {
                continue;
            }
            let cr = cr.parse::<u8>()?;
            column_ranges.push(ColumnRange::from(cr));
        }
        Ok(Self {
            auth_types,
            row_ranges,
            column_ranges,
        })
    }
    pub fn has_auth_type(&self, auth_type: AuthType) -> bool {
        self.auth_types.contains(&auth_type)
    }
    pub fn has_row_range(&self, row_range: RowRange) -> bool {
        self.row_ranges.contains(&row_range)
    }
    pub fn has_column_range(&self, column_range: ColumnRange) -> bool {
        self.column_ranges.contains(&column_range)
    }
}

#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
pub enum AuthType {
    Select,
    Insert,
    Delete,
    Update,
    Edit,
    Import,
    Export,
}
impl <'de> serde::Deserialize<'de> for AuthType {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "select" => Ok(AuthType::Select),
            "edit" => Ok(AuthType::Edit),
            "insert" => Ok(AuthType::Insert),
            "delete" => Ok(AuthType::Delete),
            "update" => Ok(AuthType::Update),
            "import" => Ok(AuthType::Import),
            "export" => Ok(AuthType::Export),
            _ => Err(serde::de::Error::custom(format!("Invalid auth type: {}", s))),
        }
    }
}
impl Display for AuthType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            AuthType::Select => write!(f, "查看"),
            AuthType::Edit => write!(f, "编辑"),
            AuthType::Insert => write!(f, "新增"),
            AuthType::Delete => write!(f, "删除"),
            AuthType::Update => write!(f, "修改"),
            AuthType::Import => write!(f, "导入"),
            AuthType::Export => write!(f, "导出"),
        }
    }
}
impl From<AuthType> for u8 {
    fn from(auth_type: AuthType) -> Self {
        match auth_type {
            AuthType::Select => 1,
            AuthType::Edit => 2,
            AuthType::Insert => 3,
            AuthType::Delete => 4,
            AuthType::Update => 5,
            AuthType::Import => 6,
            AuthType::Export => 7,
        }
    }
}
impl AuthType {
    pub fn from_str(auth_type: &str) -> Option<Self> {
        match auth_type {
            "select" => Some(AuthType::Select),
            "edit" => Some(AuthType::Edit),
            "insert" => Some(AuthType::Insert),
            "delete" => Some(AuthType::Delete),
            "update" => Some(AuthType::Update),
            "import" => Some(AuthType::Import),
            "export" => Some(AuthType::Export),
            _ => None,
        }
    }
}
impl From<u8> for AuthType {
    fn from(auth_type: u8) -> Self {
        match auth_type {
            1 => AuthType::Select,
            2 => AuthType::Edit,
            3 => AuthType::Insert,
            4 => AuthType::Delete,
            5 => AuthType::Update,
            6 => AuthType::Import,
            7 => AuthType::Export,
            _ => AuthType::Select,
        }
    }
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
pub enum RowRange {
    //本人
    OneSelf,
    //本部门
    DeptSelf,
    //上级部门
    DeptSuper,
    //全部
    All,
}
impl Default for RowRange {
    fn default() -> Self {
        RowRange::OneSelf
    }
}
impl <'de> serde::Deserialize<'de> for RowRange {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "oneself" => Ok(RowRange::OneSelf),
            "deptself" => Ok(RowRange::DeptSelf),
            "deptsuper" => Ok(RowRange::DeptSuper),
            "all" => Ok(RowRange::All),
            _ => Err(serde::de::Error::custom(format!("Invalid row range: {}", s))),
        }
    }
}
impl Display for RowRange {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            RowRange::All => write!(f, "全部"),
            RowRange::OneSelf => write!(f, "本人"),
            RowRange::DeptSelf => write!(f, "本部门"),
            RowRange::DeptSuper => write!(f, "一级部门"),
        }
    }
}
impl From<RowRange> for u8 {
    fn from(auth_type: RowRange) -> Self {
        match auth_type {
            RowRange::OneSelf => 1,
            RowRange::DeptSelf => 2,
            RowRange::DeptSuper => 3,
            RowRange::All => 4,
        }
    }
}
impl From<u8> for RowRange {
    fn from(auth_type: u8) -> Self {
        match auth_type {
            1 => RowRange::OneSelf,
            2 => RowRange::DeptSelf,
            3 => RowRange::DeptSuper,
            4 => RowRange::All,
            _ => RowRange::OneSelf,
        }
    }
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
pub enum ColumnRange {
    //所有
    All,
    //公司
    Comp,
    //公司小微
    CompSmall,
    //零售
    IndiSave,
    //零售个贷
    IndiLoan,
    //同业业务
    InterBank,
    //国际业务
    Internat,
    //绩效
    Pay,
    //费用
    Cost,
    //敏感数据
    Sensitive,
}
impl Default for ColumnRange {
    fn default() -> Self {
        ColumnRange::All
    }
}
impl <'de> serde::Deserialize<'de> for ColumnRange {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "all" => Ok(ColumnRange::All),
            "comp" => Ok(ColumnRange::Comp),
            "compsmall" => Ok(ColumnRange::CompSmall),
            "indisave" => Ok(ColumnRange::IndiSave),
            "indiloan" => Ok(ColumnRange::IndiLoan),
            "interbank" => Ok(ColumnRange::InterBank),
            "internat" => Ok(ColumnRange::Internat),
            "pay" => Ok(ColumnRange::Pay),
            "cost" => Ok(ColumnRange::Cost),
            "sensitive" => Ok(ColumnRange::Sensitive),
            _ => Err(serde::de::Error::custom(format!("Invalid column range: {}", s))),
        }
    }
}
impl Display for ColumnRange {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            ColumnRange::All => write!(f, "所有"),
            ColumnRange::Comp => write!(f, "公司"),
            ColumnRange::CompSmall => write!(f, "中小"),
            ColumnRange::IndiSave => write!(f, "零售"),
            ColumnRange::IndiLoan => write!(f, "个贷"),
            ColumnRange::InterBank => write!(f, "金融市场"),
            ColumnRange::Internat => write!(f, "交易银行"),
            ColumnRange::Pay => write!(f, "绩效"),
            ColumnRange::Cost => write!(f, "费用"),
            ColumnRange::Sensitive => write!(f, "敏感数据"),
        }
    }
}
impl From<ColumnRange> for u8 {
    fn from(auth_type: ColumnRange) -> Self {
        match auth_type {
            ColumnRange::All => 0,
            ColumnRange::Comp => 1,
            ColumnRange::CompSmall => 2,
            ColumnRange::IndiSave => 3,
            ColumnRange::IndiLoan => 4,
            ColumnRange::InterBank => 5,
            ColumnRange::Internat => 6,
            ColumnRange::Pay => 7,
            ColumnRange::Cost => 8,
            ColumnRange::Sensitive => 9,
        }
    }
}
impl From<u8> for ColumnRange {
    fn from(auth_type: u8) -> Self {
        match auth_type {
            0 => ColumnRange::All,
            1 => ColumnRange::Comp,
            2 => ColumnRange::CompSmall,
            3 => ColumnRange::IndiSave,
            4 => ColumnRange::IndiLoan,
            5 => ColumnRange::InterBank,
            6 => ColumnRange::Internat,
            7 => ColumnRange::Pay,
            8 => ColumnRange::Cost,
            9 => ColumnRange::Sensitive,
            _ => ColumnRange::All,
        }
    }
}
impl MenuItem {
    pub fn new(id: u32, name: impl AsRef<str>, component: Option<Component>,popedom: Option<Permission>,children: Vec<MenuItem>) -> Self {
        Self {
            name: name.as_ref().to_owned(),
            id,
            component,
            permission: popedom,
            children,
        }
    }
    #[cfg(feature = "ssr")]
    pub fn add_child(&mut self, child: MenuItem) {
        self.children.push(child);
    }
    #[cfg(feature = "ssr")]
    pub fn get_children(&self) -> &Vec<MenuItem> {
        &self.children
    }
}
